package com.dolphin.config.shiro;

import cn.hutool.core.map.MapUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.dolphin.commons.Constants;
import com.dolphin.commons.IpUtil;
import com.dolphin.commons.OptionCacheUtil;
import com.dolphin.config.shiro.customToken.QqToken;
import com.dolphin.model.Role;
import com.dolphin.model.User;
import com.dolphin.service.RoleService;
import com.dolphin.service.UserService;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authc.credential.SimpleCredentialsMatcher;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import java.util.Map;


/**
 * Custom shiroRealm
 *
 * @author dolphin
 */
@Component
public class QqRealm extends AuthorizingRealm {
    private final static Logger LOGGER = LoggerFactory.getLogger(QqRealm.class);
    @Autowired
    private UserService userService;
    @Autowired
    private RoleService roleService;

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) throws AuthenticationException {
        return null;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        QqToken userToken = (QqToken) token;
        String code = userToken.getCode();
        String appId = OptionCacheUtil.getValue(Constants.QQ_APP_ID);
        String appKey = OptionCacheUtil.getValue(Constants.QQ_APP_KEY);
        HttpServletRequest request = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest();
        String callbackDomain = IpUtil.basePath(request).concat("api/qqCallback");
        Map<String, Object> p1 = MapUtil.of("grant_type", "authorization_code");
        p1.put("client_id", appId);
        p1.put("client_secret", appKey);
        p1.put("code", code);
        p1.put("redirect_uri", callbackDomain);
        String resp1 = HttpUtil.get("https://graph.qq.com/oauth2.0/token", p1);
        String accessToken = JSONUtil.parseObj(resp1).getStr("access_token");


        String callback = HttpUtil.get("https://graph.qq.com/oauth2.0/me", MapUtil.of("access_token", accessToken));
        String openId = callback.substring(45, callback.length() - 6);

        Map<String, Object> p2 = MapUtil.of("access_token", accessToken);
        p2.put("oauth_consumer_key", appId);
        p2.put("openid", openId);
        JSONObject json2 = JSONUtil.parseObj(HttpUtil.get("https://graph.qq.com/user/get_user_info", p2));
        User user = userService.getUserByAccount("QQ:" + openId);
        if (user == null) {
            String isRegister = OptionCacheUtil.getValue(Constants.OPTION_WEB_IS_REGISTER);
            if (StringUtils.isNotBlank(isRegister) && isRegister.equals(String.valueOf(Constants.REGISTER_NO))) {
                LOGGER.error("Account does not exist: {}", "网站已关闭注册功能");
                throw new UnknownAccountException("网站已关闭注册功能");
            }
            String nickname = json2.getStr("nickname");
            String avatar = json2.getStr("figureurl_qq_2").replace("http://", "https://");
            user = new User();
            user.setUserName(nickname);
            user.setAvatar(avatar);
            user.setAccount("QQ:" + openId);
            user.setStatus(Constants.USER_STATUS_DEFAULT);
            //设置默认角色
            String roleCode = OptionCacheUtil.getValue(Constants.EHCACHE_KEY_WEB_REGISTER_DEFAULT_ROLE);
            if (StringUtils.isBlank(roleCode)) {
                roleCode = Constants.ROLE_USER;
            }
            Role role = roleService.getRoleByCode(roleCode);
            user.setRoleId(role.getId());
            user.setRole(role);
            userService.add(user);
        }

        return new SimpleAuthenticationInfo(user, "", getName());
    }

    @Override
    public Class getAuthenticationTokenClass() {
        return QqToken.class;
    }

    /**
     * 自定义密码验证匹配器
     */
    @PostConstruct
    public void initCredentialsMatcher() {
        setCredentialsMatcher(new SimpleCredentialsMatcher() {
            @Override
            public boolean doCredentialsMatch(AuthenticationToken authenticationToken, AuthenticationInfo authenticationInfo) {
                return true;
            }
        });
    }
}
